package club.gskj.gulimall.product.service.impl;

import club.gskj.common.constant.ProductConstant;
import club.gskj.common.to.SkuHasStockVo;
import club.gskj.common.to.SkuReductionTo;
import club.gskj.common.to.SpuBoundTo;
import club.gskj.common.to.es.SkuEsModel;
import club.gskj.common.utils.R;
import club.gskj.gulimall.product.entity.*;
import club.gskj.gulimall.product.feign.CouponFeignService;
import club.gskj.gulimall.product.feign.SearchFeignService;
import club.gskj.gulimall.product.feign.WareFeignService;
import club.gskj.gulimall.product.service.*;
import club.gskj.gulimall.product.vo.*;
import com.alibaba.fastjson.TypeReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import club.gskj.common.utils.PageUtils;
import club.gskj.common.utils.Query;

import club.gskj.gulimall.product.dao.SpuInfoDao;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    private SpuInfoDescService spuInfoDescService;

    @Autowired
    private SpuImagesService spuImagesService;

    @Autowired
    private AttrService attrService;

    @Autowired
    private ProductAttrValueService productAttrValueService;

    @Autowired
    private SkuInfoService skuInfoService;

    @Autowired
    private SkuImagesService skuImagesService;

    @Autowired
    private SkuSaleAttrValueService skuSaleAttrValueService;

    @Autowired
    private CouponFeignService couponFeignService;

    @Autowired
    private WareFeignService wareFeignService;

    @Autowired
    private SearchFeignService searchFeignService;

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );
        return new PageUtils(page);
    }

    // TODO 分布式事务回滚操作
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSpuInfo(SpuSaveVo vo) {

        // 保存基本信息 pms_spu_info
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        BeanUtils.copyProperties(vo, spuInfoEntity);
        spuInfoEntity.setCreateTime(new Date());
        spuInfoEntity.setUpdateTime(new Date());
        this.saveBaseSpuInfo(spuInfoEntity);

        // 保存spu描述图片 pms_spu_info_desc
        List<String> decript = vo.getDecript();
        SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity();
        spuInfoDescEntity.setSpuId(spuInfoEntity.getId());
        spuInfoDescEntity.setDecript(String.join(",", decript));
        spuInfoDescService.saveSpuInfoDesc(spuInfoDescEntity);

        // 保存spu图片集 pms_spu_images
        List<String> images = vo.getImages();
        spuImagesService.saveImages(spuInfoEntity.getId(), images);

        // 保存spu 的规格参数 pms_product_attr_value
        List<BaseAttrs> baseAttrs = vo.getBaseAttrs();
        List<ProductAttrValueEntity> baseAttrList = baseAttrs.stream().map(attr -> {
            ProductAttrValueEntity entity = new ProductAttrValueEntity();
            entity.setSpuId(spuInfoEntity.getId());
            entity.setAttrId(attr.getAttrId());
            AttrEntity attrEntity = attrService.getById(attr.getAttrId());
            entity.setAttrName(attrEntity.getAttrName());
            entity.setAttrValue(attr.getAttrValues());
            entity.setQuickShow(attr.getShowDesc());
            return entity;
        }).collect(Collectors.toList());

        productAttrValueService.saveBatchProductAttr(baseAttrList);

        // 保存 spu积分信息、 gulimall_sms:sms_spu_bounds
        // 调用远程coupon服务，保存会员积分
        Bounds bounds = vo.getBounds();
        SpuBoundTo spuBoundTo = new SpuBoundTo();
        BeanUtils.copyProperties(bounds, spuBoundTo);
        // 设置 spuid
        spuBoundTo.setSupId(spuInfoEntity.getId());

        R r = couponFeignService.saveSpuBounds(spuBoundTo);
        if (r.getCode() != 0) {
            log.error("远程保存sku积分信息失败!");
        }

        List<Skus> skus = vo.getSkus();
        if (skus != null && skus.size() > 0) {

            skus.forEach(item -> {

                String defaultImgUrl = "";
                List<Images> skuImages = item.getImages();
                for (Images skuImage : skuImages) {
                    if (skuImage.getDefaultImg() == 1) {
                        defaultImgUrl = skuImage.getImgUrl();
                    }
                }

                SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
                skuInfoEntity.setSkuDefaultImg(defaultImgUrl);
                BeanUtils.copyProperties(item, skuInfoEntity);
                skuInfoEntity.setBrandId(spuInfoEntity.getBrandId());
                skuInfoEntity.setCatelogId(spuInfoEntity.getCatalogId());
                skuInfoEntity.setSaleCount(0L);
                skuInfoEntity.setSpuId(spuInfoEntity.getId());

                // 保存sku信息 pms_sku_info
                skuInfoService.saveSkuInfo(skuInfoEntity);

                // skuId
                Long skuId = skuInfoEntity.getSkuId();

                List<SkuImagesEntity> skuImagesEntityList = skuImages.stream().map(skuImage -> {
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();

                    skuImagesEntity.setSkuId(skuId);
                    skuImagesEntity.setImgUrl(skuImage.getImgUrl());
                    skuImagesEntity.setDefaultImg(skuImage.getDefaultImg());

                    return skuImagesEntity;
                }).filter(skuImagesEntity -> {
                    // TODO 没有选中图片的不保存在数据库中， 即imgUrl为null
                    // 返回true就是 需要
                    return !StringUtils.isEmpty(skuImagesEntity.getImgUrl());
                }).collect(Collectors.toList());

                // 保存sku图片信息 pms_sku_images
                skuImagesService.saveBatch(skuImagesEntityList);

                List<Attr> attr = item.getAttr();
                List<SkuSaleAttrValueEntity> skuAttrList = attr.stream().map(skuAttr -> {
                    SkuSaleAttrValueEntity entity = new SkuSaleAttrValueEntity();
                    BeanUtils.copyProperties(skuAttr, entity);
                    entity.setSkuId(skuId);
                    return entity;
                }).collect(Collectors.toList());

                // 保存sku的销售属性 pms_sku_sale_attr_value
                skuSaleAttrValueService.saveBatch(skuAttrList);

                // sku的优惠、满减信息  gulimall_sms:  sms_sku_ladder,sms_sku_full_reduction,sms_member_price
                SkuReductionTo skuReductionTo = new SkuReductionTo();

                BeanUtils.copyProperties(item, skuReductionTo);
                skuReductionTo.setSkuId(skuId);

                if (skuReductionTo.getFullCount() > 0 || skuReductionTo.getFullPrice().compareTo(new BigDecimal("0")) == 1) {
                    R reduectionR = couponFeignService.saveSkuReduection(skuReductionTo);
                    if (reduectionR.getCode() != 0) {
                        log.error("远程保存sku优惠、满减信息失败!");
                    }
                }
            });
        }
    }

    @Override
    public void saveBaseSpuInfo(SpuInfoEntity spuInfoEntity) {
        this.baseMapper.insert(spuInfoEntity);
    }

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        // 封装查询条件
        QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();
        /**
         * status:
         * key:
         * brandId: 0
         * catelogId: 0
         */
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)) {
            wrapper.and((w) -> {
                w.eq("id", key).or().like("spu_name", key);
            });
        }
        // status =1 AND ( id  = 1 OR spu_name like 'ss');
        String status = (String) params.get("status");
        if (!StringUtils.isEmpty(status)) {
            wrapper.eq("publish_status", status);
        }

        String brandId = (String) params.get("brandId");
        if (!StringUtils.isEmpty(brandId) && !"0".equals(brandId)) {
            wrapper.eq("brand_id", brandId);
        }

        String catelogId = (String) params.get("catelogId");
        if (!StringUtils.isEmpty(catelogId) && !"0".equals(catelogId)) {
            wrapper.eq("catalog_id", catelogId);
        }

        IPage<SpuInfoEntity> page = this.page(new Query<SpuInfoEntity>().getPage(params), wrapper);
        return new PageUtils(page);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void spuUp(Long spuId) {

        // 1.查询spu对应的所有sku信息
        List<SkuInfoEntity> skuInfoEntityList = skuInfoService.listSkuBySpuId(spuId);

        List<Long> skuIdList = skuInfoEntityList.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());

        // TODO 查询当前sku的所有可以检索的规格属性
        List<ProductAttrValueEntity> productAttrValueEntityList = productAttrValueService.listBaseAttrForSpuBySpuId(spuId);

        List<Long> attrIds = productAttrValueEntityList.stream().map(item -> {
            return item.getId();
        }).collect(Collectors.toList());

        // 查询过滤出所有可以检索的attrId
        List<Long> searchAttrIds = attrService.listSearchAttrIds(attrIds);
        Set<Long> idSet = new HashSet<>(searchAttrIds);

        // 过滤去可以检索的规格属性
        List<SkuEsModel.Attr> BaseAttrList = productAttrValueEntityList.stream().filter(item -> {
            return idSet.contains(item.getAttrId());
        }).map(item -> {
            SkuEsModel.Attr attr = new SkuEsModel.Attr();
            BeanUtils.copyProperties(item, attr);
            return attr;
        }).collect(Collectors.toList());

        // TODO 发送远程调用，库存系统是否有库存
        Map<Long, Boolean> hasStockMap = null;
        try {
            R r = wareFeignService.hasStockBySku(skuIdList);

            if (r.getCode() == 0) {
                // 逆转为 <List<SkuHasStockVo类型
                TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<List<SkuHasStockVo>>() {
                };
                List<SkuHasStockVo> data = r.getData(typeReference);
                // 将查询的数据转为 map
                hasStockMap = data.stream().collect(Collectors.toMap(SkuHasStockVo::getSpuId, item -> item.getHasStock()));
            }
        } catch (Exception e) {
            //e.printStackTrace();
            log.error("调用远程库存服务异常！{}", e);
        }

        // 2. 封装每个sku信息
        // 因为一个spu会有多个sku，这里封装为list
        Map<Long, Boolean> finalHasStockMap = hasStockMap;
        List<SkuEsModel> collect = skuInfoEntityList.stream().map(item -> {
            // 组装ESModel对象
            SkuEsModel skuEsModel = new SkuEsModel();
            BeanUtils.copyProperties(item, skuEsModel);
            skuEsModel.setSkuPrice(item.getPrice());
            skuEsModel.setSkuImg(item.getSkuDefaultImg());

            // 设置库存信息
            // 如果 hasStockMap为空，默认设置有库存
            // hasStock
            if (finalHasStockMap != null) {
                Boolean hasStock = finalHasStockMap.get(item.getSkuId());
                skuEsModel.setHasStock(hasStock);
            } else {
                skuEsModel.setHasStock(true);
            }
            // TODO 热度评分 默认0
            // hotScore
            skuEsModel.setHotScore(0L);

            // TODO 品牌，分类、名称
            // brandName
            // brandImg
            // catelogName
            Long brandId = item.getBrandId();
            BrandEntity brandEntity = brandService.getById(brandId);
            skuEsModel.setBrandName(brandEntity.getName());
            skuEsModel.setBrandImg(brandEntity.getLogo());

            Long catelogId = item.getCatelogId();
            CategoryEntity categoryEntity = categoryService.getById(catelogId);
            skuEsModel.setCatelogName(categoryEntity.getName());

            // 设置检索属性 attrs
            skuEsModel.setAttrs(BaseAttrList);
            return skuEsModel;
        }).collect(Collectors.toList());

        // TODO 3.将ESModel数据发送到 ES进行保存， gulimall_search
        R r = searchFeignService.productStatusUp(collect);
        if (r.getCode() == 0) {
            // 远程调用成功
            // TODO 修改spu的发布状态为 已上架
            this.baseMapper.updateSpuStatus(spuId, ProductConstant.ProductStatusEnum.UP_SPU.getCode());
        } else {
            // TODO 远程调用失败,重读调用 接口幂等性；重试机制
            /**
             * feigin执行流程 SynchronousMethodHandler
             * 1.构造请求数据、将对象转换为JSON
             *      RequestTemplate template = buildTemplateFromArgs.create(argv);
             * 2.发送请求进行执行(执行成功会解码响应数据)
             *       executeAndDecode(template);
             * 3.执行请求会有重试机制
             *     while (true) {
             *       try {
             *       // 这里执行，如果不成功，会触发重试机制
             *         return executeAndDecode(template);
             *       } catch (RetryableException e) {
             *         try {
             *         // 在这里重试，有异常直接抛出、重试机制结束
             *           retryer.continueOrPropagate(e);
             *         } catch (RetryableException th) {
             *           Throwable cause = th.getCause();
             *           if (propagationPolicy == UNWRAP && cause != null) {
             *             throw cause;
             *           } else {
             *             throw th;
             *           }
             *         }
             *         if (logLevel != Logger.Level.NONE) {
             *           logger.logRetry(metadata.configKey(), logLevel);
             *         }
             *         continue;
             *       }
             */
        }
    }
}
